package com.mdinic.blogovi.service;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

@Service
class VokativImpl implements Vokativ {

    private final String[] excpetions = new String[] {};

    private static final Map<String, String> azbuka = new HashMap<String, String>();

    private static final String ONLY_LETTERS_PATTERN = "[a-zA-ZŠĐČĆŽšđčćž]";

    private static final Pattern PATTERN = Pattern.compile(ONLY_LETTERS_PATTERN, Pattern.DOTALL);

    static {
        azbuka.put("а", "a");
        azbuka.put("б", "b");
        azbuka.put("в", "v");
        azbuka.put("г", "g");
        azbuka.put("д", "d");
        azbuka.put("ђ", "đ");
        azbuka.put("е", "e");
        azbuka.put("ж", "ž");
        azbuka.put("з", "z");
        azbuka.put("и", "i");
        azbuka.put("ј", "j");
        azbuka.put("к", "k");
        azbuka.put("л", "l");
        azbuka.put("љ", "lj");
        azbuka.put("м", "m");
        azbuka.put("н", "n");
        azbuka.put("њ", "nj");
        azbuka.put("о", "o");
        azbuka.put("п", "p");
        azbuka.put("р", "r");
        azbuka.put("с", "s");
        azbuka.put("т", "t");
        azbuka.put("ћ", "ć");
        azbuka.put("у", "u");
        azbuka.put("ф", "f");
        azbuka.put("х", "h");
        azbuka.put("ц", "c");
        azbuka.put("ч", "č");
        azbuka.put("џ", "dž");
        azbuka.put("ш", "š");
        azbuka.put("А", "A");
        azbuka.put("Б", "B");
        azbuka.put("В", "V");
        azbuka.put("Г", "G");
        azbuka.put("Д", "D");
        azbuka.put("Ђ", "Đ");
        azbuka.put("Е", "E");
        azbuka.put("Ж", "Ž");
        azbuka.put("З", "Z");
        azbuka.put("И", "I");
        azbuka.put("Ј", "J");
        azbuka.put("К", "K");
        azbuka.put("Л", "L");
        azbuka.put("Љ", "LJ");
        azbuka.put("М", "M");
        azbuka.put("Н", "N");
        azbuka.put("Њ", "NJ");
        azbuka.put("О", "O");
        azbuka.put("П", "P");
        azbuka.put("Р", "R");
        azbuka.put("С", "S");
        azbuka.put("Т", "T");
        azbuka.put("Ћ", "Ć");
        azbuka.put("У", "U");
        azbuka.put("Ф", "F");
        azbuka.put("Х", "H");
        azbuka.put("Ц", "C");
        azbuka.put("Ч", "Č");
        azbuka.put("Џ", "DŽ");
        azbuka.put("Ш", "Š");
    }

    private String correctCase(String string) {
        return StringUtils.capitalize(StringUtils.lowerCase(string));
    }

    private boolean isItCir(String tekst) {
        for (Entry<String, String> entry : azbuka.entrySet()) {
            if (tekst.contains(entry.getKey())) {
                return true;
            }
        }
        return false;
    }

    public String cleanString(String input) {
        input = input.trim().replace("\"", "");

        String[] split = input.split(" ");
        input = preslovljavanje(split[0], isItCir(input));

        Matcher matcher = PATTERN.matcher(input);
        StringBuilder sb = new StringBuilder();
        while (matcher.find()) {
            sb.append(matcher.group(0));
        }

        return sb.toString();
    }

    @Override
    public String makeVokativ(String name) {
        String vokativ = "";
        boolean cirilica = isItCir(name);
        if (cirilica) {
            name = preslovljavanje(name, true);
        }

        name = cleanString(name); // sređujemo string

        for (String ex : excpetions) {
            if (ex.equalsIgnoreCase(name)) {
                return name;
            }
        }

        if (substr(name, -3).equals("TAR") || substr(name, -3).equals("DAR")) // PETAR,
            // ALEKSANDAR
            vokativ = substrReplace(name, "RE", -2);

        else if (substr(name, -3).equals("ICA") && name.length() > 4) // MILICA
                                                                      // ,
            // LJUBICA ALI NE
            // I MICA i CICA
            vokativ = substrReplace(name, "CE", -2);

        else if (substr(name, -2).equals("CA")) // MACA, CECA...
            vokativ = substrReplace(name, "CO", -2);

        else if (substr(name, -2).equals("SA")) // PERSA, BOSA
            vokativ = substrReplace(name, "SO", -2);

        else if (substr(name, -4).equals("OLAC")) // KOLAC
            vokativ = substrReplace(name, "OČE", -4);

        else if (substr(name, -4).equals("ALAC")) // ZNALAC
            vokativ = substrReplace(name, "ALČE", -4);

        else if (substr(name, -4).equals("ILAC")) // MISLILAC
            vokativ = substrReplace(name, "IOČE", -4);

        else if (substr(name, -4).equals("ELAC")) // ŽETELAC
            vokativ = substrReplace(name, "EOČE", -4);

        else if (substr(name, -3).equals("SAC")) // PISAC
            vokativ = substrReplace(name, "ŠČE", -3);

        else if (substr(name, -3).equals("RAC")) // MUDRAC
            vokativ = substrReplace(name, "RČE", -3);

        else if (substr(name, -3).equals("VAC")) // VALJEVAC
            vokativ = substrReplace(name, "VČE", -3);

        else if ((substr(name, -2).equals("KA")) && (name.length() > 4)) // DARINKA,
            // MILKA,
            // BORKA, ALI
            // NE I RAKA,
            // MIKA
            vokativ = name;

        else if (substr(name, -2).equals("JA") && !substr(name, -3).equals("IJA") && !substr(name, -3).equals("DJA")
                && !substr(name, -3).equals("NJA")) // MAJA ALI NE I MARIJA,
                                                    // SANJA,
            // NITI PEDJA (NE PEĐA)
            vokativ = substrReplace(name, "JO", -2);

        else if (substr(name, -2).equals("VA") || substr(name, -2).equals("DA") || substr(name, -2).equals("BA")
                || substr(name, -2).equals("KA")) // SAVA, DADA, SLOBA, RAKA
            vokativ = substrReplace(name, "O", -1);

        else if (substr(name, -3).equals("ARA") || substr(name, -3).equals("ERA") || substr(name, -3).equals("ORA")) // PERA,
            // DARA,
            // BORA
            vokativ = substrReplace(name, "RO", -2);

        else if (substr(name, -1).equals("K")) // CUTUK
            vokativ = substrReplace(name, "Č", -1) + "E";

        else if (substr(name, -1).equals("G")) // PREDRAG
            vokativ = substrReplace(name, "Ž", -1) + "E";

        // ć, đ, č, dž, š, ž, lj, nj, j
        else if (mySubstr(name, -1).equals("Ć") || mySubstr(name, -1).equals("Đ") || mySubstr(name, -1).equals("Č")
                || mySubstr(name, -2).equals("DŽ") || mySubstr(name, -1).equals("Š") || mySubstr(name, -1).equals("Ž")
                || mySubstr(name, -2).equals("LJ") || mySubstr(name, -2).equals("NJ") || mySubstr(name, -1).equals("J"))
            vokativ = name + "U";

        else if (substr(name, -1).equals("A") || substr(name, -1).equals("O") || substr(name, -1).equals("E")
                || substr(name, -1).equals("I"))// VANJA,
            // MARKO,
            // MILE,
            // MIKI
            vokativ = name;
        else
            vokativ = name + "E";

        // ako koristimo ćirilicu vraćamo napravljeni vokativ iz latinice u
        // ćirilicu
        // if (cirilica) {
        // vokativ = preslovljavanje(vokativ, false);
        // }

        // izvor je algoritam

        // vraćamo sređen vokativ (mala slova, prvo veliko)
        return correctCase(vokativ);
    }

    public String preslovljavanje(String tekst, boolean cirToLat) {

        StringBuilder sb = new StringBuilder();
        if (cirToLat) {
            for (int i = 0; i < tekst.length() - 1; i++) {
                sb.append(azbuka.get(tekst.substring(i, i + 1)));
            }
        } else {
            return tekst;
        }

        return sb.toString();
    }

    private String substr(String s, int index) {
        if (s.length() < -index) {
            return StringUtils.EMPTY;
        }
        return s.substring(s.length() + index).toUpperCase();
    }

    private String substrReplace(String ime, String end, int index) {
        return ime.substring(0, ime.length() + index) + end;
    }

    private String mySubstr(String str, int start) {
        return str.substring(0, str.length() + start);
    }

}
